# -*- coding: utf-8 -*-
import os, sys, logging, passwords
parent_dir = os.path.abspath(os.path.dirname(__file__))
logging.info('parent_dir: %s', parent_dir)
if parent_dir not in sys.path:
    sys.path.insert(0, parent_dir)

# Remove the standard version of Django
if 'django' in sys.modules and sys.modules['django'].VERSION < (1, 2):
    for k in [k for k in sys.modules
              if k.startswith('django\.') or k == 'django']:
        del sys.modules[k]

from djangoappengine import boot
boot.setup_threading()
boot.setup_project()
boot.setup_logging()
boot.setup_env()

import django.core.handlers.wsgi
from google.appengine.ext.webapp import util
from django.conf import settings
os.environ.update(boot.env_ext)
#------
#from django.conf import settings
#from google.appengine.ext import db
from djapp.models import *
from comparable_wave import *
from wave_catalog import *
from waveapi import robot
from waveapi import appengine_robot_runner
from django.shortcuts import render_to_response
from django.template import loader, RequestContext
from djapp.catalog_section import SectionLevel, Section

class DBController:
  tags = [{"category": u"1st lvl", "elements": [u'тег1.1', u'тег1.2']}, {"category": u"2nd lvl", "elements": [u'тег2.1', u'тег2.2']}]
  subtags = {0: {"tags": [],
                 "wave_id": "googlewave.com!w+6juI-EdvC",   
                 "header": u"Тестовый каталог",
                 "no_group": True}}
  extended_tag = {}

  def __init__(self):
    
    self.subtags = {}
    self.extended_tag = {}
    self.group_subtags = {}
    
    """
    self.tags = DBController.tags
    self.subtags = DBController.subtags
    self.extended_tag = DBController.extended_tag
    self.no_group = [0]
    """
    self.section_dict = {}
    self.other_section_idx = {}
    tags = {}
    tmp_dict = {}
    
    for sec in CatalogSection.objects.all(): #DBController.section: 
        tmp_dict[sec.section_level] = (sec.id, Section(sec.section_level, sec.section_name))
        tags[sec.id] = [] #[sec.id]
    
    i = 0
    for lvl in Level.objects.all().order_by('level'): #sort Level.objects. DBController.tags: 
        tags[lvl.catalog_section_id.id].append({'name': lvl.name, 
                                            'level': lvl.level,  
                                            'structure': self._get_tag_list(lvl.tags, sort = True)})
        i += 1
    
    logging.warning("tmp_dict: %s" % tmp_dict)
    logging.warning("tags: %s" % tags)
    #for sorted list of tmp_dict by level
    for lvl_idx in tmp_dict:
        if tags[tmp_dict[lvl_idx][0]]:
            self.section_dict[lvl_idx] = tmp_dict[lvl_idx][1]
            self.section_dict[lvl_idx].set_structure(tags[tmp_dict[lvl_idx][0]])
        else:
            self.other_section_idx[lvl_idx] = None
            self.section_dict[lvl_idx] = tmp_dict[lvl_idx][1]
    
    self.no_group = []
    i = 0
    for cat in Category.objects.all():
      self.subtags[i] = {"tags_and": self._get_tag_list(cat.tags_and, lower = True),
                         "tags_or": self._get_tag_list(cat.tags_or, lower = True),
                         "wave_id": cat.wave_id, 
                         "header": cat.header, 
                         "no_group": cat.no_group }
      if cat.no_group:
          self.no_group.append(i)
      i += 1
    for tag in ExtendedTag.objects.all():
      self.extended_tag[tag.name.lower()] = set(self._get_tag_list(tag.tags, lower = True))      
    
    for ind in self.subtags.keys():  #user group
      if not self.subtags[ind]["no_group"] and (self.subtags[ind]["tags_and"] or self.subtags[ind]["tags_or"]):
        self.group_subtags[ind] = {'tags_and': self.subtags[ind]["tags_and"], 'tags_or': self.subtags[ind]['tags_or']}
    #"""
      
  def _get_tag_list(self, tags, lower = False, sort = False):
    tag_list = []
    if tags:
      if lower:
        tag_list = [t.strip().lower() for t in tags.split(',')]
      else:
        tag_list = [t.strip() for t in tags.split(',')]
      if sort:
        tag_list.sort()
    return tag_list

  def put(self, wavelet):
    """Puts wave to database."""
    wave_tags = wavelet.tags.serialize()
    lower_tags = [q.strip().lower() for q in wave_tags]
    wave = Wave(title = wavelet.title or '<no title>', 
                wave_id = wavelet.wave_id, 
                tags = lower_tags)
    try:
      wave.save()
    except: # Exception as exc:
      logging.error("Failed to put wave %s to db." % wavelet.wave_id)
    
  def delete(self, wave_id):
    """Deletes wave from database by its ID."""
    try:
      q = Wave.objects.filter(wave_id = wave_id) 
      for result in q:
        result.delete()
    except:
      logging.error("Failed to delete wave %s from db." % wave_id)            
      
  def _get_wave_copies(self, wave):
    if wave.tags:
      wave_lower_tags = set(wave.tags)
    else:
      wave_lower_tags = set([])
      
    new_wave_tags = wave_lower_tags.copy() #extended_tag       
    for tag in wave_lower_tags: 
      if tag in self.extended_tag:
        new_wave_tags = new_wave_tags.union(self.extended_tag[tag])          
    wave_lower_tags = new_wave_tags
    
    
    group_index = set()  #user catalog
    for j in self.group_subtags.keys():
        add_and = True
        for tag_and in self.group_subtags[j]['tags_and']:
            if tag_and not in wave_lower_tags:
                add_and = False
        add_or = False
        for tag_or in self.group_subtags[j]['tags_or']:
            if tag_or in wave_lower_tags:
                add_or = True
                break
        if add_and and (add_or or not self.group_subtags[j]['tags_or']):
            group_index.add(j)

    wave_tags = {}
    for sec_idx in self.section_dict:
        wave_tags[sec_idx] = [[]]
        splited_wave_tags = wave_tags[sec_idx] #add wave to several tag
        cur_section = self.section_dict[sec_idx]
        for lvl in range(len(cur_section)):
          lvl_length = len(splited_wave_tags) #length of repeated tags in previous lvl
          cur_length = 0
          tag_idx = 0
          for tag in cur_section[lvl]:
            tag = tag.lower()
            if tag in wave_lower_tags:
              for i in range(lvl_length):
                if cur_length > 0:
                  splited_wave_tags.append(splited_wave_tags[i][:-1])
                  splited_wave_tags[-1].append(tag_idx)
                else:
                  splited_wave_tags[i].append(tag_idx)
              cur_length += 1
            tag_idx += 1
          if cur_length == 0:
              for i in range(lvl_length):
                  splited_wave_tags[i].append(len(cur_section[lvl]))
        
        empty_lvl = []
        for l in range(len(cur_section)):
            empty_lvl.append(len(cur_section[l]))
        if splited_wave_tags[0] == empty_lvl:
            wave_tags[sec_idx] = [[]]
    return wave_tags, group_index   
      
      
  def get_cmp_wave_id(db_wave_id):
    pass     

  def get_waves(self):
      wave_list = Wave.objects.all()
      wave_dict = {}
      for w in wave_list:
          wave_dict[w.wave_id] = w.tags
      return wave_dict
    
  def lower(self):
    wave_list = Wave.objects.all()
    for w in wave_list:    
      if w.tags:
        w.tags = [t.strip().lower() for t in w.tags]
        w.save()

  def get_all(self):
    """ Returns: dictionary of WaveCatalog object's list 
        [length depends on the section number] for each user category."""
    waves = Wave.objects.all()
    wave_catalog = {}
    for k in self.subtags.keys(): #initializing each catalog
        wave_catalog[k] = {}
        for lvl in self.section_dict:
            wave_catalog[k][lvl] = WaveCatalog(structure = self.section_dict[lvl].structure, 
                                               title = self.section_dict[lvl].name)
    
    for wave in waves:
        splited_wave, group_index = self._get_wave_copies(wave)
        no_section = True
        for wave_section_idx in splited_wave: #adding to non empty sectors            
            for wave_tag in splited_wave[wave_section_idx]:
                  if wave_tag:
                      no_section = False
                      for group in group_index: #put wave in each user category
                          wave_catalog[group][wave_section_idx].put(wave_id = wave.wave_id, 
                                                                    title = wave.title, 
                                                                    tag_indexes = wave_tag)
                     
                      if len(group_index) == 0: #no user group
                        for cat in self.no_group:
                          wave_catalog[cat][wave_section_idx].put(wave_id = wave.wave_id, 
                                                                  title = wave.title, 
                                                                  tag_indexes = wave_tag)
        if no_section: #adding to sectors without structure
            for group in group_index: #put wave in each user category
                for idx in self.other_section_idx:
                    wave_catalog[group][idx].put(wave_id = wave.wave_id, #index of OTHER-section 
                                                 title = wave.title, tag_indexes = [])
             
            if len(group_index) == 0: #no user group
                for cat in self.no_group:
                    for idx in self.other_section_idx:
                        wave_catalog[cat][idx].put(wave_id = wave.wave_id, #index of OTHER-section 
                                                   title = wave.title, tag_indexes = [])
    for group_idx in wave_catalog:
        for sec_idx in wave_catalog[group_idx]:
            logging.warning("Before. %s, section: %s, len: %d" % (self.subtags[group_idx]['header'], 
                                                                 wave_catalog[group_idx][sec_idx].title, 
                                                                 len(wave_catalog[group_idx][sec_idx])))
    return wave_catalog
  